#include <iostream>
#include <string>
#include <vector>
#include <unistd.h>
#include <cstring>
#include <cstdlib>
#include <ctime>
#include <sys/wait.h>
#include <sys/types.h>
#include "Task.hpp"

class Channel
{
public:
    Channel(int wfd, pid_t subprocessid, const std::string &channelname)
        : _wfd(wfd), _subprocessid(subprocessid), _channelname(channelname)
    {}

    ~Channel() {}

    int getWfd()
    {
        return _wfd;
    }

    pid_t getSubprocessId()
    {
        return _subprocessid;
    }

    std::string getChannerlName()
    {
        return _channelname;
    }

    void CloseChannel()
    {
        close(_wfd);
    }

    void Wait()
    {
        pid_t rid = waitpid(_subprocessid, nullptr, 0);
        if (rid > 0)
        {
            std::cout << "wait: " << rid << " success!" << std::endl;
        }
    }

private:
    int _wfd;
    pid_t _subprocessid;
    std::string _channelname;
};

// 创建信道和子进程
void CreaterChannelAndSub(std::vector<Channel> *channels, int num, task_t task)
{
    for (int i = 0; i < num; i++)
    {
        // 创建管道
        int pipefd[2] = {0};
        int n = pipe(pipefd);
        if (n < 0)
        {
            std::cerr << "errno: " << errno << "errmsg: " << strerror(errno) << std::endl;
            exit(-1);
        }

        // 创建子进程
        pid_t id = fork();
        if (id == 0)
        {
            // child -> read
            close(pipefd[1]); // 关掉不需要的fd
            dup2(pipefd[0], 0);
            task();
            close(pipefd[0]); // 通信结束
            exit(0);
        }

        // father
        close(pipefd[0]);

        std::string channel_name = "channel_id: " + std::to_string(i);
        channels->push_back(Channel(pipefd[1], id, channel_name));
    }
}

// 获取信道
int NextChannel(int channelnum)
{
    static int next = 0;
    int channel = next;
    next++;
    next %= channelnum;
    return channel;
}

// 给对应的信道发操作码
void SendTaskCommand(Channel &channel, int task_code)
{
    write(channel.getWfd(), &task_code, sizeof(task_code));
}

// 控制进程一次
void CtrlProcessonce(std::vector<Channel> &channels)
{
    sleep(1);
    int task_code = SelectTask();                        // 选择一个任务码
    int channel_index = NextChannel(channels.size());    // 选择一个信道
    SendTaskCommand(channels[channel_index], task_code); // 发送
    std::cout << std::endl;
    std::cout << "task_code: " << task_code << "  channel : " << channels[channel_index].getChannerlName() << "  sub_pid: "
              << channels[channel_index].getSubprocessId() << std::endl;
}

// 控制进程
void CtrlProcess(std::vector<Channel> &channels, int times = -1)
{
    if (times == -1)
    {
        while (true)
        {
            CtrlProcessonce(channels);
        }
    }
    else
    {
        while (times--)
        {
            CtrlProcessonce(channels);
        }
    }
}

// 关闭信道和等待子进程退出
void CleanUpChannel(std::vector<Channel> &channels)
{
    //  关闭所有的写端
    for (auto &channel : channels)
    {
        channel.CloseChannel();
    }

    // 等待子进程
    for (auto &channel : channels)
    {
        channel.Wait();
    }
}

int main(int argc, char *argv[])
{
    // 判断是否命令行参数合法
    if (argc != 2)
    {
        std::cerr << "command error" << std::endl;
        return -1;
    }

    // 获取进程池的数量
    int num = std::stoi(argv[1]);

    std::vector<Channel> channels;
    LoadTask(); // 加载任务
    // 1、创建信道和子进程
    CreaterChannelAndSub(&channels, num, work);;

    // 2、通过channel控制子进程
    // a.选择任务 b.选择一个进程
    CtrlProcess(channels, 5);

    // 3、关闭管道和子进程
    CleanUpChannel(channels);

    // test
    // for (auto &channel : channels)
    // {
    //     std::cout << "----------------------------------------------" << std::endl;
    //     std::cout << "channel_id: " << channel.getSubprocessId() \
    //     << "  channel_name: " << channel.getChannerlName() << "  Sub_pid: " \
    //     << channel.getWfd() << std::endl;
    // }

    // sleep(100);
    return 0;
}
